import Vue from 'vue';
import Vuex from 'vuex';
import axios from 'axios';
import example from '../example/swagger';

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    active: 'Home',
    swagger: '2.0',
    host: '',
    basePath: '',
    title: '',
    description: '',
    version: '',
    contact: {},
    licence: {},
    tags: [],
    paths: {},
    definitions: {},
    vtags: [],
    vpaths: {}
  },
  getters: {
    active: state => state.active,
    swagger: state => state.swagger,
    host: state => state.host,
    basePath: state => state.basePath,
    title: state => state.title,
    description: state => state.description,
    version: state => state.version,
    contact: state => state.contact,
    licence: state => state.licence,
    tags: state => state.tags,
    paths: state => state.paths,
    definitions: state => state.definitions,
    vtags: state => state.vtags,
    vpaths: state => state.vpaths,
    pathsByTag: state => state.vpaths[state.active]
  },
  mutations: {
    setActive: (state, active) => state.active = active,
    setSwagger: (state, swagger) => state.swagger = swagger,
    setHost: (state, host) => state.host = host,
    setBasePath: (state, basePath) => state.basePath = basePath,
    setTitle: (state, title) => state.title = title,
    setDescription: (state, description) => state.description = description,
    setVersion: (state, version) => state.version = version,
    setContact: (state,contact) => state.contact = contact,
    setLicence: (state, licence) => state.licence = licence,
    setTags: (state, tags) => state.tags = tags,
    setPaths: (state, paths) => state.paths = paths,
    setVtags: (state, vtags) => state.vtags = vtags,
    setVpaths: (state, vpaths) => state.vpaths = vpaths,
    setDefinitions: (state, definitions) => state.definitions = definitions,
  },
  actions: {
    active(context, active) {
      context.commit('setActive', active);
    },
    loadApiDocument(context) {
      if (process.env.NODE_ENV === 'development') {
        context.dispatch('parseDoc', example);
      } else if (process.env.NODE_ENV === 'production') {
        const url = window.location.protocol + '//' + window.location.host + '/v2/api-docs';
        axios.get(url).then(resp => {
          if (resp.status === 200) {
            context.dispatch('parseDoc', resp.data);
          }
        });
      }
    },
    parseDoc(context, doc) {
      context.commit('setSwagger', doc.swagger);
      context.commit('setHost', doc.host);
      context.commit('setBasePath', doc.basePath);
      context.commit('setTitle', doc.info ? doc.info.title : undefined);
      context.commit('setDescription', doc.info ? doc.info.description : undefined);
      context.commit('setVersion', doc.info ? doc.info.version : undefined);
      context.commit('setContact', doc.info ? doc.info.contact : undefined);
      context.commit('setLicence', doc.info ? doc.info.licence : undefined);
      context.commit('setTags', doc.tags);
      context.commit('setVtags', doc.tags);
      context.commit('setDefinitions', doc.definitions);

      const tagPaths = {};
      Object.keys(doc.paths).forEach(location => {
        const methodPaths = doc.paths[location];
        Object.keys(methodPaths).forEach(method => {
          const path = methodPaths[method];

          // map struct parameter name list
          const expandParameters = path.parameters ?
            path.parameters.filter(
              parameter => parameter.in === 'body' && parameter.schema !== undefined && (parameter.schema.$ref !== undefined || parameter.schema.type === 'array' || parameter.schema.type === 'object')
            ).map(parameter => parameter.name) : [];

          // responses transfer: {} -> []
          const responses = path.responses;
          const newResponses = [];
          const expandResponses = [];
          if (responses !== undefined && responses !== null) {
            Object.keys(responses).forEach(code => {
              const response = responses[code];
              if (response.schema !== undefined && (response.schema.$ref !== undefined || response.schema.type === 'array' || response.schema.type === 'object')) {
                expandResponses.push(code);
              }

              const newResponse = {
                name: code,
                ...response
              };
              newResponses.push(newResponse);
            });
          }

          // errorCode transfer: {} -> []
          const codes = path['x-error-code'];
          const newCodes = [];
          if (codes !== undefined && codes != null) {
            Object.keys(codes).forEach(code => {
              const newCode = {
                code: code,
                description: codes[code]
              };
              newCodes.push(newCode);
            });
          }

          const newPath = {
            ...path,
            location: location,
            method: method,
            responses: newResponses,
            errorCodes: newCodes,
            expandResponses: expandResponses,
            expandParameters: expandParameters
          };

          // transfer to => { tag: [] }
          path.tags.forEach(tag => {
            if (tagPaths[tag] === undefined || tagPaths[tag] === null) {
              tagPaths[tag] = [];
            }
            tagPaths[tag].push(newPath);
          })
        });
      });

      // sort
      Object.keys(tagPaths).forEach(tag => {
        tagPaths[tag] = tagPaths[tag].sort((a, b) => {
          return parseInt(a['x-sort']) - parseInt(b['x-sort']);
        });
      });
      context.commit('setPaths', tagPaths);
      context.commit('setVpaths', tagPaths);
    },
    search({ commit, state }, keywords) {
      const vpaths = {};
      Object.keys(state.paths).forEach(tag => {
        const pathList = state.paths[tag];
        const vpathList = pathList.filter(path => {
          return path.location.indexOf(keywords) >= 0 ||
            (path.summary && path.summary.indexOf(keywords) >= 0) ||
            (path.description && path.description.indexOf(keywords) >= 0)
        });

        if (vpathList && vpathList.length > 0) {
          vpaths[tag] = vpathList;
        }
      });

      const vtags = state.tags.filter(tag => {
        return Object.keys(vpaths).indexOf(tag.name) >= 0;
      });

      commit('setVtags', vtags);
      commit('setVpaths', vpaths);
    },
    clearSearch({ commit, state }) {
      commit('setVtags', state.tags);
      commit('setVpaths', state.paths);
    }
  }
});

export default store;
